package com.aneliya.view.component.box;

import java.awt.Component;
import java.awt.Container;
import java.util.ArrayList;

import javax.swing.SwingUtilities;

import com.aneliya.formatter.IFormatImpl;
import com.aneliya.formatter.IFormatable;
import com.aneliya.formatter.StringFormatImpl;
import com.aneliya.layout.VerticalBoxLayoutManager;
import com.aneliya.view.component.renderer.IDataRenderer;
import com.aneliya.view.component.renderer.IInvalidationRenderer;

public class VerticalBox<E extends IDataRenderer> extends Container 
		implements IDataRenderer,IInvalidationRenderer {
	private static final long serialVersionUID = 1L;
	
	private ArrayList<Component> items;
	
	private Class<E> itemRendererClass;
	public Class<E> getItemRendererClass() {
		return itemRendererClass;
	}
	public void setItemRendererClass(Class<E> value) {
		itemRendererClass = value;
	}
	
	private IFormatImpl itemDataFormatImpl = new StringFormatImpl();
	public IFormatImpl getItemDataFormatImpl() {
		return itemDataFormatImpl;
	}
	public void setItemDataFormatImpl(IFormatImpl itemDataFormatterImpl) {
		this.itemDataFormatImpl = itemDataFormatterImpl;
	}
	
	private Boolean isDataChanged = false;
	private ArrayList<Object> data;
	public Object getData() {
		return data;
	}
	@SuppressWarnings("unchecked")
	public void setData(Object value) {
		if (value != null) {
			ArrayList<Object> newData = (ArrayList<Object>)((ArrayList<Object>) value).clone();
			if (newData.size() > 0 && (data == null || !data.equals(newData))) {
				data = newData;
				isDataChanged = true;
				invalidateRenderer();
			}
		}
	}

	public VerticalBox() {
		super();
		setLayout(new VerticalBoxLayoutManager());
		items = new ArrayList<Component>();
	}

	public void invalidateRenderer() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					validateRenderer();
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		});	
	}

	public void validateRenderer() throws InstantiationException, IllegalAccessException {
		if (isDataChanged) {
			isDataChanged = false;
			recycleItems();
			updateItemsData();
			validate();
		}
	}
	
	private void recycleItems() throws InstantiationException, IllegalAccessException {
		if (items.size() < data.size()) {
			addItems();
		}
		
		if (items.size() > data.size()) {
			removeItems();
		}
	}
	
	private void updateItemsData() {
		for (int i = 0; i < data.size(); i++) {
			Object itemData = data.get(i);
			IDataRenderer item = (IDataRenderer) items.get(i);
			item.setData(itemData);
		}
	}
	
	private void addItems() throws InstantiationException, IllegalAccessException {
		int count = data.size() - items.size();
		for (int i = 0; i < count; i++) {
			Component item = (Component)itemRendererClass.newInstance();
			item.setSize(getWidth(), getHeight());
			
			if (item instanceof IFormatable) {
				IFormatable formatableItem = (IFormatable) item;
				formatableItem.setFormatImpl(itemDataFormatImpl);
			}
			
			items.add(item);
			add(item);
		}
	}
	
	private void removeItems() {
		int count = items.size() - data.size();
		int itemsCount = items.size();
		for (int i = items.size() - 1; i >= itemsCount - count ; i--) {
			Component item = items.remove(i);
			item.setVisible(false);
			remove(item);
		}
	}

}
